﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;

namespace Red.Controls.Tile
{
    public partial class TileImpl : UserControl
    {
        #region Dependency Properties

        public static readonly DependencyProperty StatusProperty =
        DependencyProperty.Register( "Status", typeof( string ), typeof( TileImpl ) );

        public static readonly DependencyProperty IconWidthProperty =
        DependencyProperty.Register( "IconWidth", typeof( double ), typeof( TileImpl ) );

        public static readonly DependencyProperty IconHeightProperty =
        DependencyProperty.Register( "IconHeight", typeof( double ), typeof( TileImpl ) );

        public static readonly DependencyProperty PrependedMenuItemsProperty =
        DependencyProperty.Register( "PrependedMenuItems", typeof( ICollection<object> ), typeof( TileImpl ) );

        #endregion Dependency Properties

        #region Private Data

        private const double ANIMATION_TIME = 0.4;

        private TranslateTransform _transform;

        #endregion Private Data

        #region Public Properties

        public string Status
        {
            get { return (string)GetValue( StatusProperty ); }
            set { SetValue( StatusProperty, value ); }
        }

        public double IconWidth
        {
            get { return (double)GetValue( IconWidthProperty ); }
            set { SetValue( IconWidthProperty, value ); }
        }

        public double IconHeight
        {
            get { return (double)GetValue( IconHeightProperty ); }
            set { SetValue( IconHeightProperty, value ); }
        }

        public ICollection<object> PrependedMenuItems
        {
            get { return (ICollection<object>)GetValue( PrependedMenuItemsProperty ); }
            set { SetValue( PrependedMenuItemsProperty, value ); }
        }

        #endregion Public Properties

        #region C-Tor

        public TileImpl()
        {
            SetValue( PrependedMenuItemsProperty, new List<object>() );

            InitializeComponent();
            SizeChanged += TileImpl_SizeChanged;
        }

        #endregion C-Tor

        #region Private Methods

        private void UpdateIconSize()
        {
            Tile tile = DataContext as Tile;

            if ( tile?.Canvas?.Height > 0 )
            {
                double ratio = tile.Canvas.Width / tile.Canvas.Height;

                IconWidth = IconHeight * ratio;
            }
        }

        #endregion Private Methods

        #region Public Methods

        public void RenderAt( double x, double y )
        {
            if ( _transform == null )
            {
                _transform = new TranslateTransform();
                RenderTransform = _transform;
            }

            ClearAnimation();

            _transform.X = x;
            _transform.Y = y;
        }

        public void AnimateTo( double x, double y )
        {
            if ( _transform == null )
            {
                _transform = new TranslateTransform();
                RenderTransform = _transform;
            }

            DoubleAnimation xAnim = new DoubleAnimation( RenderTransform.Value.OffsetX, x, TimeSpan.FromSeconds( ANIMATION_TIME ) );
            DoubleAnimation yAnim = new DoubleAnimation( RenderTransform.Value.OffsetY, y, TimeSpan.FromSeconds( ANIMATION_TIME ) );

            BackEase easingFunc = new BackEase();
            easingFunc.EasingMode = EasingMode.EaseInOut;
            xAnim.EasingFunction = easingFunc;
            yAnim.EasingFunction = easingFunc;

            _transform.BeginAnimation( TranslateTransform.XProperty, xAnim );
            _transform.BeginAnimation( TranslateTransform.YProperty, yAnim );
        }

        public void ClearAnimation()
        {
            if ( _transform != null )
            {
                _transform.BeginAnimation( TranslateTransform.XProperty, null );
                _transform.BeginAnimation( TranslateTransform.YProperty, null );

                _transform.X = 0;
                _transform.Y = 0;
            }
        }

        #endregion Public Methods

        #region Event Handlers

        private void TileImpl_SizeChanged( object sender, SizeChangedEventArgs e )
        {
            UpdateIconSize();
        }

        private static void DependencyPropertyChanged( DependencyObject d, DependencyPropertyChangedEventArgs e )
        {
            TileImpl tile = (TileImpl)d;

            tile.UpdateIconSize();
        }

        private void Tile_Click( object sender, RoutedEventArgs e )
        {
            Click?.Invoke( (Tile)DataContext, this );
            System.Diagnostics.Debug.Print( $"Tile clicked" );
        }

        private void Tile_MouseDoubleClick( object sender, MouseButtonEventArgs e )
        {
            DoubleClick?.Invoke( (Tile)DataContext, this );
            System.Diagnostics.Debug.Print( $"Tile double clicked" );
            e.Handled = true;
        }

        private void Resize_Small_Click( object sender, RoutedEventArgs e )
        {
            RequestResize?.Invoke( this, 1, 1 );
        }

        private void Resize_Wide_Click( object sender, RoutedEventArgs e )
        {
            RequestResize?.Invoke( this, 1, 2 );
        }

        private void Resize_Medium_Click( object sender, RoutedEventArgs e )
        {
            RequestResize?.Invoke( this, 2, 2 );
        }

        private void Resize_Large_Click( object sender, RoutedEventArgs e )
        {
            RequestResize?.Invoke( this, 2, 3 );
        }

        private void Delete_Click( object sender, RoutedEventArgs e )
        {
            RequestDelete?.Invoke( (Tile)DataContext, this );
        }

        #endregion Event Handlers

        public delegate void ClickHandler( Tile tile, TileImpl impl );
        public delegate void RequestResizeHandler( TileImpl impl, int rowspan, int columnspan );

        public event ClickHandler Click;
        public event ClickHandler DoubleClick;
        public event ClickHandler RequestDelete;
        public event RequestResizeHandler RequestResize;

        #region Object Overrides

        public override string ToString() { return ( (Tile)DataContext ).ToString(); }

        #endregion Object Overrides
    }
}
